package base

import (
	"context"
	"github.com/zeromicro/go-zero/core/load"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest"
	"github.com/zeromicro/go-zero/zrpc"
	"google.golang.org/grpc"
	"payme3000/framework/config_center"
	"payme3000/framework/errorx"
	frameworkRecover "payme3000/framework/recover"
	"reflect"
	"sync"
)

var (
	sheddingStat *load.SheddingStat
	sheddingLock sync.Mutex
)

type (
	// IServer 外部访问接口模块
	IServer interface {
		IModule
		ISetAppConf
		ISetConfigCenter
		placeholderServer()
	}

	// ZeroServerConf go-zero的server配置
	ZeroServerConf struct {
		RpcServerConf *zrpc.RpcServerConf
		RestConf      *rest.RestConf
	}

	// Server IServer的基础实现
	Server struct {
		Module

		ApiServer *rest.Server    // api server
		RpcServer *zrpc.RpcServer // rpc server

		AppConf        *AppConf                    // 启动配置, 依赖项
		ConfigCenter   *config_center.ConfigCenter // 配置中心
		ZeroServerConf *ZeroServerConf             // 解析ZeroConf后的zero server配置

		RpcServerRegister      func(*grpc.Server) // grpc的register func, 有提供意味着要启用rpc server
		RpcServerStartCallback func()             // grpc server启动时调用, 注意不是启动后
		RouterRegister         []IRouter          // 注册路由处理器, 有提供意味着要启用api server
		ApiServerRunOptionList []rest.RunOption   // api server创建时的额外选项

		runningRouterList []IRouter // 注册成功running的router
	}
)

func (s *Server) Init(ctx context.Context) {
	s.Module.Init(ctx)
	s.ZeroServerConf = &ZeroServerConf{
		RestConf:      &rest.RestConf{},
		RpcServerConf: &zrpc.RpcServerConf{},
	}
}

func (s *Server) Start() error {
	// Server的执行分为以下阶段
	// 阶段1 创建rpc server
	// 阶段2 创建api server
	// 阶段3 启动server

	// 阶段1
	// 阶段1.1 加载配置
	// 阶段1.2 检查配置

	// 阶段2
	if len(s.RouterRegister) > 0 {
		routeNum := 0
		for _, router := range s.RouterRegister {
			for _, group := range router.Groups() {
				routeNum += len(group.Routes)
			}
		}

		if routeNum > 0 {
			if s.AppConf.ConfigCenterServiceConf != nil && s.AppConf.ConfigCenterServiceConf.RestConf != nil {
				// 设置默认值
				s.ZeroServerConf.RestConf.MaxConns = 10000
				s.ZeroServerConf.RestConf.MaxBytes = 1048576
				s.ZeroServerConf.RestConf.Timeout = s.AppConf.DefaultRequestTimeout
				s.ZeroServerConf.RestConf.CpuThreshold = 900
				s.ZeroServerConf.RestConf.Middlewares.Trace = true
				s.ZeroServerConf.RestConf.Middlewares.Log = true
				s.ZeroServerConf.RestConf.Middlewares.Prometheus = false // 暂时禁用
				s.ZeroServerConf.RestConf.Middlewares.MaxConns = true
				s.ZeroServerConf.RestConf.Middlewares.Breaker = false // 暂时禁用
				s.ZeroServerConf.RestConf.Middlewares.Shedding = true
				s.ZeroServerConf.RestConf.Middlewares.Timeout = true
				s.ZeroServerConf.RestConf.Middlewares.Recover = true
				s.ZeroServerConf.RestConf.Middlewares.Metrics = true
				s.ZeroServerConf.RestConf.Middlewares.MaxBytes = true
				s.ZeroServerConf.RestConf.Middlewares.Gunzip = true

				// 从配置中心获取配置
				s.ZeroServerConf.RestConf.Host = s.AppConf.ConfigCenterServiceConf.RestConf.Host
				s.ZeroServerConf.RestConf.Port = s.AppConf.ConfigCenterServiceConf.RestConf.Port
				if s.AppConf.ConfigCenterServiceConf.RestConf.Timeout > 0 {
					s.ZeroServerConf.RestConf.Timeout = s.AppConf.ConfigCenterServiceConf.RestConf.Timeout
				}
			}

			// 必须提供监听地址
			if s.ZeroServerConf.RestConf.Host == "" || s.ZeroServerConf.RestConf.Port <= 0 {
				return errorx.Errorf(context.Background(), "Host of Port not found")
			}

			// 创建api server
			if apiServer, err := rest.NewServer(
				*s.ZeroServerConf.RestConf,
				s.ApiServerRunOptionList...,
			); err != nil {
				return errorx.Throw(context.Background(), err)
			} else {
				s.ApiServer = apiServer
			}

			// 注册路由
			for _, router := range s.RouterRegister {
				if len(router.Groups()) > 0 {
					router.Init(s.Ctx)
					// 注册路由失败不中断服务, 仅打印错误日志
					if err := router.Start(); err != nil {
						logx.Errorf("start router error with router:%s", reflect.TypeOf(router).Elem().String())
					} else {
						for _, group := range router.Groups() {
							s.ApiServer.AddRoutes(group.Routes, group.Options...)
						}
						s.runningRouterList = append(s.runningRouterList, router)
					}
				}
			}
		}
	}

	// 阶段3 ApiServer Start()后会block, 需要启动协程处理
	if s.ApiServer != nil {
		go frameworkRecover.WithRecover(func() {
			defer s.AddDone()()
			logx.Infof("start api server, listening on:%s:%d", s.ZeroServerConf.RestConf.Host, s.ZeroServerConf.RestConf.Port)
			s.ApiServer.Start()
			logx.Infof("api server stopped")
		})
	}

	return nil
}

func (s *Server) Stop() {
	if s.ApiServer != nil {
		s.ApiServer.Stop()
	}

	if s.RpcServer != nil {
		s.RpcServer.Stop()
	}

	if len(s.runningRouterList) > 0 {
		for _, router := range s.runningRouterList {
			router.Stop()
		}
	}

	s.Module.Stop()
}

func (s *Server) SetAppConf(appConf *AppConf) {
	s.AppConf = appConf
}

func (s *Server) SetConfigCenter(configCenter *config_center.ConfigCenter) {
	s.ConfigCenter = configCenter
}

func (s *Server) placeholderServer() {}

func (r *Router) Routes() []rest.Route {
	return nil
}

func (r *Router) Options() []rest.RouteOption {
	return nil
}
